/*
 *   Copyright 2012, Thomas Kerber
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
package milk.skimmed;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * The extraction instructions to fall back to if none are provided.
 * 
 * Aims to successfully extract as many mods as possible.
 * @author Thomas Kerber
 * @version 1.0.0
 */
public class StandardExtractionInstructions implements ExtractionInstructions{
    
    /**
     * The folders to extract.
     */
    static final Set<String> namesForExtract =
            new HashSet<String>(Arrays.asList(new String[]{
        "texturepacks",
        "resources",
        "bin"
    }));
    
    /**
     * Return value of extractJarps()
     */
    private File[] jarpLocations;
    /**
     * Return value of extractClassRoots()
     */
    private JarpCreationInfo[] jcis;
    /**
     * Map of files to copy (from key to value)
     */
    private Map<File, File> extracts = new HashMap<File, File>();
    /**
     * List of tmp dirs to erase after completion.
     */
    private List<File> tmpDirs = new ArrayList<File>();
    
    @Override
    public void init(File extractFrom, File minecraftRoot,
            List<Jarp> availableJarps, String origName) throws IOException{
        
        List<File> jarps = Util.findAllWithEnding(extractFrom, ".jarp");
        jarpLocations = jarps.toArray(new File[jarps.size()]);
        
        Set<File> jciRoots = Util.findClassRoots(extractFrom);
        List<JarpCreationInfo> jcis = new ArrayList<JarpCreationInfo>();
        for(File f : jciRoots)
            jcis.add(getJCI(f, f, extractFrom, origName));
        this.jcis = jcis.toArray(new JarpCreationInfo[jcis.size()]);
        
        // If no jarps or classes have been found up to now, any jars are seen
        // as class roots.
        List<File> jars = Util.findAllWithEnding(extractFrom, ".jar");
        if(jarpLocations.length == 0 && this.jcis.length == 0){
            for(File j : jars){
                File extracted = milk.jpatch.Util.extractZip(j);
                getJCI(extracted, j, extractFrom, origName);
                tmpDirs.add(extracted);
            }
        }
        // Else all jars are extracted into the minecraft bin dir.
        else{
            File binD = new File(Skimmed.MINECRAFT_ROOT, "bin");
            for(File j : jars){
                extracts.put(j, new File(binD, j.getName()));
            }
        }
        
        for(File f : extractFrom.listFiles()){
            if(f.isDirectory())
                extractDirs(f);
        }
    }
    
    /**
     * Extracts directories with certain names.
     * @param dir The directory to recurse through.
     */
    private void extractDirs(File dir){
        // If the dir is one of the extracts, add and terminate.
        if(namesForExtract.contains(dir.getName())){
            extracts.put(dir, new File(Skimmed.MINECRAFT_ROOT, dir.getName()));
            return;
        }
        for(File f : dir.listFiles()){
            if(f.isDirectory())
                extractDirs(f);
        }
    }
    
    /**
     * Generates JCI.
     * @param jRoot The class root.
     * @param jRootLocation The "true" location of jRoot (in case it was
     *     extracted to a tmp dir)
     * @param root The root dir for the zip.
     * @param name The name of the mod.
     * @return The generated JCI.
     * @throws IOException
     */
    // Difference betw. jRoot and jRootLocation: if jRoot is extracted,
    // jRootLocation notes its previous name.
    private JarpCreationInfo getJCI(File jRoot, File jRootLocation, File root,
            String name) throws IOException{
        String fname = name + "[" +
                root.toURI().relativize(jRootLocation.toURI()) + "]";
        Set<Jarp> reqs = KeyHunter.resolveAssocs(jRoot);
        return new JarpCreationInfo(jRoot, reqs.toArray(new Jarp[reqs.size()]),
                fname);
    }
    
    @Override
    public void extractFiles(File extractFrom, File minecraftRoot)
            throws IOException{
        for(Map.Entry<File, File> e : extracts.entrySet()){
            Util.copy(e.getKey(), e.getValue());
        }
    }
    
    @Override
    public File[] extractJarps(File extractFrom) throws IOException{
        return jarpLocations;
    }
    
    @Override
    public JarpCreationInfo[] extractClassRoots(File extractFrom,
            List<Jarp> availableJarps) throws IOException{
        return jcis;
    }
    
    @Override
    public void close() throws IOException{
        for(File f : tmpDirs){
            milk.jpatch.Util.remDir(f);
        }
    }
    
}
